﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Security.Cryptography;

namespace DACK_MHTTUD_0912008_0912493
{
    public partial class UCAes : UserControl
    {
        public UCAes()
        {
            InitializeComponent();
            Init();
        }

        string inputFile;
        string outputFile;
        int paddingModeIndex;
        int modeOfOperationIndex;
        string IV;
        string password;
        List<string> paddingMode = new List<string>();
        List<string> operationMode = new List<string>();
        private void Init()
        {
            paddingMode.Add("PKCS7");
            paddingMode.Add("ISO10126");
            paddingMode.Add("ANSIX923");
            comboBoxPadding.DataSource = paddingMode;
            comboBoxPaddingDecrypt.DataSource = paddingMode;

            operationMode.Add("CBC");
            operationMode.Add("ECB");
            operationMode.Add("OFB");
            operationMode.Add("CTS");
            operationMode.Add("CFB");
            comboBoxOperation.DataSource = operationMode;
            comboBoxOperationDecrypt.DataSource = operationMode;

            inputFile = "";
            outputFile = "";
            paddingModeIndex = -1;
            modeOfOperationIndex = -1 ;
            IV = "";
            password = "";
        }

        private void btnOpenFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog openDialog = new OpenFileDialog();
            openDialog.Title = "Open file to encrypt";
            openDialog.ShowDialog();
            txtInput.Text = openDialog.FileName;
        }

        private void btnSaveFile_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.Title = "Path of output file";
            saveFileDialog1.ShowDialog();
            txtOutput.Text = saveFileDialog1.FileName;
        }

        private bool Check()
        {
            if (!File.Exists(inputFile))
            {
                MessageBox.Show(" Invalid input path! ");
                return false;
            }

            if (IV.Length != 16)
            {
                MessageBox.Show(" Length of IV must be 16");
                return false;
            }

            if (password.Length != 16)
            {
                MessageBox.Show(" Length of Password must be 16");
                return false;
            }

            if (paddingModeIndex == -1 || modeOfOperationIndex == -1)
            {
                MessageBox.Show(" Please choose mode");
                return false;
            }

            return true;
        }

        private void btnEncrypt_Click(object sender, EventArgs e)
        {
            inputFile = txtInput.Text;
            outputFile = txtOutput.Text;
            paddingModeIndex = comboBoxPadding.SelectedIndex;
            modeOfOperationIndex = comboBoxOperation.SelectedIndex;
            IV = txtIV.Text;
            password = txtPass.Text;

            if (Check())
            {
                try
                {
                    RijndaelEncrypt(inputFile, outputFile, paddingModeIndex, modeOfOperationIndex, password, password, "SHA1", 2, IV, 128);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }            
        }

        private void RijndaelEncrypt(string inputFile,
                                   string outputFile,//
                                   int paddingMode,// Selected Index of ComboBox
                                   int modeOfOperation,// Selected Index of ComboBox
                                   string passPhrase,
                                   string saltValue,
                                   string hashAlgorithm,
                                   int passwordIterations,
                                   string initVector,
                                   int keySize)
        {

            byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);          

            FileStream inStream, outStream;
            inStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read);
            outStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write);

            // Create Password
            PasswordDeriveBytes password = new PasswordDeriveBytes(
                passPhrase, saltValueBytes, hashAlgorithm, passwordIterations);

            byte[] keyBytes = password.GetBytes(keySize / 8);

            RijndaelManaged symmetricKey = new RijndaelManaged();

            // option

            switch (modeOfOperation)
            {
                case 0:
                    symmetricKey.Mode = CipherMode.CBC;
                    break;
                case 1:
                    symmetricKey.Mode = CipherMode.ECB;
                    break;
                case 2:
                    symmetricKey.Mode = CipherMode.OFB;
                    break;
                case 3:
                    symmetricKey.Mode = CipherMode.CTS;
                    break;
                case 4:
                    symmetricKey.Mode = CipherMode.CFB;
                    break;
            }
            switch (paddingMode)
            {
                case 0:
                    symmetricKey.Padding = PaddingMode.PKCS7;
                    break;
                case 1:
                    symmetricKey.Padding = PaddingMode.ANSIX923;                    
                    break;
                case 2:
                    symmetricKey.Padding = PaddingMode.ISO10126;
                    break;
            }

            ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);            

            CryptoStream cryptoStream = new CryptoStream(outStream,
                encryptor, CryptoStreamMode.Write);

            byte[] byteBuffer = new byte[100];

            long nTotalByteInput = inStream.Length;
            long nTotalByteWritten = 0;
            int nCurReadLen = 0;
            while (nTotalByteWritten < nTotalByteInput)
            {
                nCurReadLen = inStream.Read(byteBuffer, 0, byteBuffer.Length);
                cryptoStream.Write(byteBuffer, 0, nCurReadLen);
                nTotalByteWritten += nCurReadLen;
            }        

            cryptoStream.FlushFinalBlock();            
            cryptoStream.Close();
            MessageBox.Show("Encrypt successfully!");
        }

        private void btnDecrypt_Click(object sender, EventArgs e)
        {
            inputFile = txtInput_Decrypt.Text;
            outputFile = txtOutput_Decrypt.Text;
            paddingModeIndex = comboBoxPaddingDecrypt.SelectedIndex;
            modeOfOperationIndex = comboBoxOperationDecrypt.SelectedIndex;
            IV = txtIV_Decrypt.Text;
            password = txtPassword.Text;

            if (Check())
            {
                try
                {
                    RjinDaelDecrypt(inputFile, outputFile, modeOfOperationIndex, paddingModeIndex, password, password, "SHA1", 2, IV, 128);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private string RjinDaelDecrypt(string inputFile,
            string outputFile,
            int modeOfOperation,
            int paddingMode,
            string passPhrase,
            string saltValue,
            string hashAlgorithm,
            int passwordIterations,
            string initVector,
            int keySize)
        {
            byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);

            FileStream inStream, outStream;
            inStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read);
            outStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write);          

            PasswordDeriveBytes password = new PasswordDeriveBytes(
                passPhrase,
                saltValueBytes,
                hashAlgorithm,
                passwordIterations);

            byte[] keyBytes = password.GetBytes(keySize / 8);
            RijndaelManaged symetricKey = new RijndaelManaged();

            switch (modeOfOperation)
            {
                case 0:
                    symetricKey.Mode = CipherMode.CBC;
                    break;
                case 1:
                    symetricKey.Mode = CipherMode.ECB;
                    break;
                case 2:
                    symetricKey.Mode = CipherMode.OFB;
                    break;
                case 3:
                    symetricKey.Mode = CipherMode.CTS;
                    break;
                case 4:
                    symetricKey.Mode = CipherMode.CFB;
                    break;
            }
            switch (paddingMode)
            {
                case 0:
                    symetricKey.Padding = PaddingMode.PKCS7;
                    break;
                case 1:
                    symetricKey.Padding = PaddingMode.ANSIX923;
                    break;
                case 2:
                    symetricKey.Padding = PaddingMode.ISO10126;
                    break;
            }


            ICryptoTransform decryptor = symetricKey.CreateDecryptor(
                keyBytes,
                initVectorBytes);           

            CryptoStream cryptoStream = new CryptoStream(outStream,
                decryptor,
                CryptoStreamMode.Write);

            int bufferLen = 100;
            byte[] buffer = new byte[100];
            int bytesRead;
            do
            {
                bytesRead = inStream.Read(buffer, 0, bufferLen);
                cryptoStream.Write(buffer, 0, bytesRead);
            }
            while (bytesRead != 0);

            cryptoStream.Close();
            inStream.Close();
            outStream.Close();
            MessageBox.Show("Decrypt successfully");
            return "OK";
        }

        private void button3_Click(object sender, EventArgs e)
        {
            OpenFileDialog openDialog = new OpenFileDialog();
            openDialog.Title = "Open file to decrypt";
            openDialog.ShowDialog();
            txtInput_Decrypt.Text = openDialog.FileName;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.Title = "Path of output file";
            saveFileDialog1.ShowDialog();
            txtOutput_Decrypt.Text = saveFileDialog1.FileName;
        }
    }
}
